/************************************************************
 * Filename: GameStateMgr.cpp
 * Purpose: Game state manager implementation.
 * (will probably get rid of this later)
 * Author: Jeremy Kings
 * Revision: 2 (17 November 2010)
 * Base: GameStateMgr.cpp - CS529 Project 3
 *
 * Copyright 2010, Digipen Institute of Technology
 ************************************************************/
#include "Precompiled.h"
#include "GameStateMgr.h"

namespace Engine
{
	// global variables to keep track the current, previous and next game state
	unsigned	gGameStateInit;
	unsigned	gGameStateCurr;
	unsigned	gGameStatePrev;
	unsigned	gGameStateNext;

	GameStateManager::GameStateManager(GameState state)
	{
		// set the initial game state
		gGameStateInit = state;

		// reset the current, previous and next game
		gGameStateCurr = 
		gGameStatePrev = 
		gGameStateNext = gGameStateInit;
	}

	void GameStateManager::AddSystem(System* sys)
	{
		systems.push_back(sys);
	}

	void GameStateManager::RunLoop()
	{
		handler = new MessageHandler(&systems);

		// Game loop
		while(gGameStateCurr != GS_QUIT)
		{
			// If not restarting, load the gamestate
			if(gGameStateCurr != GS_RESTART)
				Load();
			else
				gGameStateNext = gGameStateCurr = gGameStatePrev;

			// Initialize the gamestate
			Init();

			while(gGameStateCurr == gGameStateNext)
				Update();
		
			Free();

			if(gGameStateNext != GS_RESTART)
				Unload();

			gGameStatePrev = gGameStateCurr;
			gGameStateCurr = gGameStateNext;
		}
	}

	// "Load" function of this state
	void GameStateManager::Load()
	{
		for(SysIt it = systems.begin(); it < systems.end(); ++it)
			(*it)->Load();
	}

	// "Initialize" function of this state
	void GameStateManager::Init()
	{
		// initialize systems
		for(SysIt it = systems.begin(); it < systems.end(); ++it)
			(*it)->Init();

		prevTime = timeGetTime();
	}

	// "Update" function of this state
	void GameStateManager::Update()
	{
		float frameTime = CapFramerate();
		//float frameTime = 1.0f/60.0f;

		// Use this frame time estimate for update
		for(SysIt it = systems.begin(); it < systems.end(); ++it)
			(*it)->Update(frameTime);
	}

	void GameStateManager::Free()
	{
		for(SysIt it = systems.begin(); it < systems.end(); ++it)
			(*it)->Free();
	}

	void GameStateManager::Unload()
	{
		for(SysIt it = systems.begin(); it < systems.end(); ++it)
			(*it)->Unload();
	}

	GameStateManager::~GameStateManager()
	{
		delete handler;

		for(unsigned i = 0; i < systems.size(); ++i)
			delete systems[systems.size()-i-1];

		systems.clear();
	}

	float GameStateManager::CapFramerate()
	{
		// Get current time (milliseconds)
		unsigned currTime = timeGetTime();
		// Calculate frame time from previous update to now, convert to seconds
		unsigned diff = currTime - prevTime;

		// Wait if necessary (in order to cap framerate)
		if(static_cast<float>(diff) < (1.0f/FPS)*1000.0f) 
		{
			Sleep(((1.0f/FPS)*1000.0f) - diff); // NOTE: not thread-safe
			diff = (currTime = timeGetTime()) - prevTime;
		}

		prevTime = currTime;

		return diff / 1000.0f;
	}
}